using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Infrastructure.Tcp;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models.Messages;
using System.Runtime.InteropServices;
using System.Text;

namespace SumerCoreDevOps.ExecuteNodeApi.Services;

/// <summary>
/// 节点注册服务
/// </summary>
public class NodeRegistrationService : IHostedService
{
    private readonly ILogger<NodeRegistrationService> _logger;
    private readonly TcpMultiMasterClient _tcpClient;
    private readonly IConfiguration _configuration;
    private readonly NodeConfigPersistenceService _persistenceService;
    private long _nodeId;
    private string? _nodeKey;

    public long NodeId => _nodeId;

    public NodeRegistrationService(
        ILogger<NodeRegistrationService> logger,
        TcpMultiMasterClient tcpClient,
        IConfiguration configuration,
        NodeConfigPersistenceService persistenceService)
    {
        _logger = logger;
        _tcpClient = tcpClient;
        _configuration = configuration;
        _persistenceService = persistenceService;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        try
        {
            // 监听消息
            _tcpClient.OnMessageReceived += HandleMessageAsync;

            // 尝试加载保存的配置
            var savedConfig = await _persistenceService.LoadConfigAsync();

            if (savedConfig != null)
            {
                _logger.LogInformation("✅ 发现已保存的节点配置，尝试自动连接并认证...");

                // 只有在有保存的配置时才尝试连接
                await _tcpClient.ConnectAsync(cancellationToken);
                _logger.LogInformation("已连接到 {Count} 个主节点", _tcpClient.GetConnectedMasters().Count);

                // 使用保存的认证信息重连
                _nodeId = savedConfig.NodeId;
                _nodeKey = savedConfig.NodeKey;

                await AuthenticateWithSavedConfigAsync(savedConfig);
            }
            else
            {
                // 检查是否有命令行提供的JoinToken
                var joinToken = _configuration.GetValue<string>("Server:JoinToken");

                if (!string.IsNullOrEmpty(joinToken))
                {
                    _logger.LogInformation("🔑 检测到JoinToken，开始连接并注册到主节点...");

                    // 连接到主节点
                    await _tcpClient.ConnectAsync(cancellationToken);
                    _logger.LogInformation("已连接到 {Count} 个主节点", _tcpClient.GetConnectedMasters().Count);

                    // 进行首次注册
                    await RegisterNodeAsync();
                }
                else
                {
                    _logger.LogInformation("📋 未找到保存的配置");
                    _logger.LogInformation("🌐 节点已启动，等待通过浏览器注册页面完成首次注册");
                    _logger.LogInformation("💡 请在浏览器中访问注册链接完成节点注册");
                }
            }

            _logger.LogInformation("节点注册服务已启动");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "节点注册服务启动失败");
            throw;
        }
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _tcpClient.Dispose();
        _logger.LogInformation("节点注册服务已停止");
        await Task.CompletedTask;
    }

    private async Task RegisterNodeAsync()
    {
        var nodeConfig = _configuration.GetSection("Node");
        var serverConfig = _configuration.GetSection("Server");

        // 如果没有配置NodeKey，生成一个新的
        _nodeKey = nodeConfig.GetValue<string>("Key") ?? Guid.NewGuid().ToString();

        var registerMessage = new NodeRegisterMessage
        {
            JoinToken = serverConfig.GetValue<string>("JoinToken"), // 可选
            NodeKey = _nodeKey,
            NodeName = nodeConfig.GetValue<string>("Name") ?? Environment.MachineName,
            SupportedEnvironments = nodeConfig.GetSection("Environments").Get<List<string>>() ?? [],
            HardwareInfo = new NodeHardwareInfo
            {
                CpuCores = Environment.ProcessorCount,
                TotalMemoryMB = GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 1024 / 1024,
                OperatingSystem = Environment.OSVersion.ToString(),
                Architecture = RuntimeInformation.ProcessArchitecture.ToString()
            }
        };

        // 向所有已连接的主节点发送注册请求
        await _tcpClient.SendToAllAsync(TcpMessageType.NodeRegister, registerMessage);

        _logger.LogInformation("已向所有主节点发送节点注册请求: NodeKey={NodeKey}, Name={Name}",
            registerMessage.NodeKey, registerMessage.NodeName);
    }

    private async Task AuthenticateWithSavedConfigAsync(NodeConfig config)
    {
        var authMessage = new NodeAuthMessage
        {
            NodeId = config.NodeId,
            NodeKey = config.NodeKey,
            ConnectionToken = config.ConnectionToken,
            NodeName = config.NodeName,
            HardwareInfo = new NodeHardwareInfo
            {
                CpuCores = Environment.ProcessorCount,
                TotalMemoryMB = GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 1024 / 1024,
                OperatingSystem = Environment.OSVersion.ToString(),
                Architecture = RuntimeInformation.ProcessArchitecture.ToString()
            }
        };

        // 向所有已连接的主节点发送认证请求
        await _tcpClient.SendToAllAsync(TcpMessageType.NodeAuth, authMessage);

        _logger.LogInformation("已向所有主节点发送节点认证请求: NodeId={NodeId}, NodeKey={NodeKey}",
            config.NodeId, config.NodeKey);
    }

    private async Task HandleMessageAsync(string masterId, TcpMessageType messageType, object body)
    {
        _logger.LogInformation("NodeRegistrationService.HandleMessageAsync called: MessageType={MessageType}, BodyType={BodyType}",
            messageType, body?.GetType().FullName ?? "null");

        if (messageType == TcpMessageType.RegisterResponse && body is RegisterResponseMessage response)
        {
            _logger.LogInformation("Processing RegisterResponse: Success={Success}", response.Success);

            if (response.Success)
            {
                _nodeId = response.NodeId;
                _logger.LogInformation("节点注册成功: NodeId={NodeId}, Token={Token}",
                    response.NodeId, response.Token);

                // 保存配置
                if (!string.IsNullOrEmpty(response.ConnectionToken) && !string.IsNullOrEmpty(_nodeKey))
                {
                    var serverConfig = _configuration.GetSection("Server");
                    var nodeConfig = _configuration.GetSection("Node");

                    var config = new NodeConfig
                    {
                        NodeId = response.NodeId,
                        NodeKey = _nodeKey,
                        NodeName = nodeConfig.GetValue<string>("Name") ?? Environment.MachineName,
                        ConnectionToken = response.ConnectionToken,
                        ServerHost = serverConfig.GetValue<string>("Host") ?? "localhost",
                        ServerPort = serverConfig.GetValue<int>("Port", 9090),
                        SavedAt = DateTime.UtcNow
                    };

                    await _persistenceService.SaveConfigAsync(config);
                    _logger.LogInformation("节点配置已保存，下次启动将自动重连");
                }
            }
            else
            {
                _logger.LogError("节点注册失败: {Error}", response.ErrorMessage);
            }
        }
        else if (messageType == TcpMessageType.AuthResponse && body is AuthResponseMessage authResponse)
        {
            if (authResponse.Success)
            {
                _logger.LogInformation("节点认证成功: NodeId={NodeId}", authResponse.NodeId);

                // 如果返回了新的ConnectionToken，更新配置
                if (!string.IsNullOrEmpty(authResponse.NewConnectionToken))
                {
                    var config = await _persistenceService.LoadConfigAsync();
                    if (config != null)
                    {
                        config.ConnectionToken = authResponse.NewConnectionToken;
                        config.SavedAt = DateTime.UtcNow;
                        await _persistenceService.SaveConfigAsync(config);
                        _logger.LogInformation("认证令牌已更新");
                    }
                }
            }
            else
            {
                _logger.LogError("节点认证失败: {Error}，尝试重新注册...", authResponse.ErrorMessage);

                // 认证失败，删除旧配置，尝试重新注册
                _persistenceService.DeleteConfig();
                await RegisterNodeAsync();
            }
        }
        else if (messageType == TcpMessageType.ConfigurationChanged && body is ConfigurationChangedMessage configMsg)
        {
            _logger.LogInformation("收到配置变更通知: {ConfigKey} = {NewValue}, 需要重连: {RequireReconnect}",
                configMsg.ConfigKey, configMsg.NewValue, configMsg.RequireReconnect);

            // 如果需要重新连接（通常是TCP端口变更）
            if (configMsg.RequireReconnect && configMsg.NewTcpPort.HasValue)
            {
                _logger.LogWarning("TCP服务器端口已变更，但多主节点客户端不支持动态端口变更。");
                _logger.LogWarning("请重启执行节点以使用新的配置。");

                // 多主节点客户端通过服务发现自动获取最新端口信息，无需手动重连
            }
            else
            {
                _logger.LogInformation("配置变更不需要重新连接: {Description}", configMsg.Description);
            }
        }

        await Task.CompletedTask;
    }
}
